﻿namespace Microsoft.VisualStudio.ServiceModel.DomainServices.Tools
{
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.ServiceModel.Configuration;
    using System.ServiceModel.DomainServices.Hosting;
    using System.Web.Configuration;
    using System.Xml;
    using System.Xml.Linq;

    internal class WebConfigUtil
    {
        private System.Configuration.Configuration _configuration;
        private const string DomainServicesFullSectionName = "system.serviceModel/domainServices";
        private const string DomainServicesSectionName = "domainServices";
        private const string FalseAttributeValue = "false";
        private const string ServiceHostingEnvironmentFullSectionName = "system.serviceModel/serviceHostingEnvironment";
        private const string SystemServiceModelSectionName = "system.serviceModel";
        private const string SystemWebServerSectionName = "system.webServer";
        private const string ValidateIntegratedModeConfigurationAttributeName = "validateIntegratedModeConfiguration";
        private const string ValidationSectionName = "validation";

        internal WebConfigUtil(System.Configuration.Configuration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException("configuration");
            }
            this._configuration = configuration;
        }

        internal void AddEndpointDeclaration(string endpointName, string endpointFactoryTypeName)
        {
            if (!string.IsNullOrEmpty(endpointName) && !string.IsNullOrEmpty(endpointFactoryTypeName))
            {
                bool created = false;
                DomainServicesSection orCreateDomainServicesSection = this.GetOrCreateDomainServicesSection(out created);
                if (orCreateDomainServicesSection != null)
                {
                    if (!created)
                    {
                        orCreateDomainServicesSection.Endpoints.Add(new ProviderSettings(endpointName, endpointFactoryTypeName));
                    }
                    else
                    {
                        string rawXml = orCreateDomainServicesSection.SectionInformation.GetRawXml();
                        if (string.IsNullOrEmpty(rawXml))
                        {
                            rawXml = "<domainServices><endpoints /></domainServices>";
                        }
                        XDocument xdoc = CreateXDoc(rawXml);
                        XElement element = xdoc.Element("domainServices");
                        XElement element2 = (element == null) ? null : element.Element("endpoints");
                        if (element2 != null)
                        {
                            XElement content = new XElement("add");
                            content.Add(new XAttribute("name", endpointName));
                            content.Add(new XAttribute("type", endpointFactoryTypeName));
                            element2.Add(content);
                            rawXml = CreateRawXml(xdoc);
                            orCreateDomainServicesSection.SectionInformation.SetRawXml(rawXml);
                        }
                    }
                }
            }
        }

        internal void AddHttpModule(string domainServiceModuleTypeName)
        {
            if (!string.IsNullOrEmpty(domainServiceModuleTypeName))
            {
                HttpModulesSection section = (HttpModulesSection) this._configuration.GetSection("system.web/httpModules");
                if (section != null)
                {
                    section.Modules.Add(new HttpModuleAction(BusinessLogicClassConstants.DomainServiceModuleName, domainServiceModuleTypeName));
                }
            }
        }

        internal void AddModuleToWebServer(string domainServiceModuleTypeName)
        {
            SectionInformation sectionInformation = this.GetOrCreateSystemWebServerSection().SectionInformation;
            string rawXml = sectionInformation.GetRawXml();
            if (!string.IsNullOrEmpty(rawXml))
            {
                XDocument xdoc = CreateXDoc(rawXml);
                XElement element = xdoc.Element("system.webServer");
                XElement content = element.Element("modules");
                if (content == null)
                {
                    content = new XElement("modules");
                    element.Add(content);
                }
                if (content.Attribute("runAllManagedModulesForAllRequests") == null)
                {
                    XAttribute attribute = new XAttribute("runAllManagedModulesForAllRequests", "true");
                    content.Add(attribute);
                }
                XElement element3 = new XElement("add", new object[] { new XAttribute("name", BusinessLogicClassConstants.DomainServiceModuleName), new XAttribute("preCondition", BusinessLogicClassConstants.ManagedHandler), new XAttribute("type", domainServiceModuleTypeName) });
                content.Add(element3);
                rawXml = CreateRawXml(xdoc);
                sectionInformation.SetRawXml(rawXml);
            }
        }

        internal void AddValidateIntegratedModeToWebServer()
        {
            SectionInformation sectionInformation = this.GetOrCreateSystemWebServerSection().SectionInformation;
            string rawXml = sectionInformation.GetRawXml();
            if (!string.IsNullOrEmpty(rawXml))
            {
                XDocument xdoc = CreateXDoc(rawXml);
                XElement element = xdoc.Element("system.webServer");
                XElement content = element.Element("validation");
                if (content == null)
                {
                    content = new XElement("validation");
                    element.Add(content);
                }
                XAttribute attribute = content.Attribute("validateIntegratedModeConfiguration");
                if (attribute != null)
                {
                    attribute.SetValue("false");
                }
                else
                {
                    attribute = new XAttribute("validateIntegratedModeConfiguration", "false");
                    content.Add(attribute);
                }
                rawXml = CreateRawXml(xdoc);
                sectionInformation.SetRawXml(rawXml);
            }
        }

        private static string CreateRawXml(XDocument xdoc)
        {
            string str = null;
            if (xdoc == null)
            {
                return str;
            }
            using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
            {
                XmlWriterSettings settings = new XmlWriterSettings {
                    OmitXmlDeclaration = true
                };
                using (XmlWriter writer2 = XmlWriter.Create(writer, settings))
                {
                    xdoc.WriteTo(writer2);
                }
                return writer.ToString();
            }
        }

        private static XDocument CreateXDoc(string rawXml)
        {
            XDocument document;
            if (rawXml == null)
            {
                return null;
            }
            using (StringReader reader = new StringReader(rawXml))
            {
                using (XmlReader reader2 = XmlReader.Create(reader))
                {
                    document = XDocument.Load(reader2);
                }
            }
            return document;
        }

        internal bool DoWeNeedToAddHttpModule()
        {
            HttpModulesSection section = (HttpModulesSection) this._configuration.GetSection("system.web/httpModules");
            return ((section == null) || !section.Modules.OfType<HttpModuleAction>().Any<HttpModuleAction>(a => string.Equals(a.Name, BusinessLogicClassConstants.DomainServiceModuleName, StringComparison.OrdinalIgnoreCase)));
        }

        internal bool DoWeNeedToAddModuleToWebServer()
        {
            IgnoreSection section = this._configuration.GetSection("system.webServer") as IgnoreSection;
            if (section != null)
            {
                SectionInformation sectionInformation = section.SectionInformation;
                string str = (sectionInformation == null) ? null : sectionInformation.GetRawXml();
                if (string.IsNullOrEmpty(str))
                {
                    return true;
                }
                XElement element = CreateXDoc(str).Element("system.webServer");
                if (element != null)
                {
                    element = element.Element("modules");
                    if (element == null)
                    {
                        return true;
                    }
                    IEnumerable<XElement> source = element.Elements("add");
                    if (source == null)
                    {
                        return false;
                    }
                    return !source.Any<XElement>(e => (((string) e.Attribute("name")) == BusinessLogicClassConstants.DomainServiceModuleName));
                }
            }
            return true;
        }

        internal bool DoWeNeedToValidateIntegratedModeToWebServer()
        {
            IgnoreSection section = this._configuration.GetSection("system.webServer") as IgnoreSection;
            if (section != null)
            {
                SectionInformation sectionInformation = section.SectionInformation;
                string str = (sectionInformation == null) ? null : sectionInformation.GetRawXml();
                if (string.IsNullOrEmpty(str))
                {
                    return true;
                }
                XElement element = CreateXDoc(str).Element("system.webServer");
                if (element != null)
                {
                    element = element.Element("validation");
                    XAttribute attribute = (element == null) ? null : element.Attribute("validateIntegratedModeConfiguration");
                    if (attribute != null)
                    {
                        return !string.Equals(attribute.Value, "false", StringComparison.OrdinalIgnoreCase);
                    }
                    return true;
                }
            }
            return true;
        }

        internal static string GetDomainServiceModuleTypeName()
        {
            return typeof(DomainServiceHttpModule).AssemblyQualifiedName;
        }

        internal static string GetODataEndpointFactoryTypeName()
        {
            return typeof(ODataEndpointFactory).AssemblyQualifiedName;
        }

        internal DomainServicesSection GetOrCreateDomainServicesSection(out bool created)
        {
            created = false;
            DomainServicesSection section = this._configuration.GetSection("system.serviceModel/domainServices") as DomainServicesSection;
            if (section == null)
            {
                ServiceModelSectionGroup orCreateServiceModelSectionGroup = this.GetOrCreateServiceModelSectionGroup();
                section = this._configuration.GetSection("system.serviceModel/domainServices") as DomainServicesSection;
                if (section == null)
                {
                    section = new DomainServicesSection {
                        SectionInformation = { AllowDefinition = ConfigurationAllowDefinition.MachineToApplication, RequirePermission = false }
                    };
                    orCreateServiceModelSectionGroup.Sections.Add("domainServices", section);
                    created = true;
                }
            }
            return section;
        }

        internal ServiceModelSectionGroup GetOrCreateServiceModelSectionGroup()
        {
            ServiceModelSectionGroup sectionGroup = this._configuration.GetSectionGroup("system.serviceModel") as ServiceModelSectionGroup;
            if (sectionGroup == null)
            {
                sectionGroup = new ServiceModelSectionGroup();
                this._configuration.SectionGroups.Add("system.serviceModel", sectionGroup);
            }
            return sectionGroup;
        }

        internal IgnoreSection GetOrCreateSystemWebServerSection()
        {
            IgnoreSection section = this._configuration.GetSection("system.webServer") as IgnoreSection;
            if (section == null)
            {
                section = new IgnoreSection();
                this._configuration.Sections.Add("system.webServer", section);
            }
            SectionInformation sectionInformation = section.SectionInformation;
            if (string.IsNullOrEmpty(sectionInformation.GetRawXml()))
            {
                string rawXml = "<system.webServer/>";
                sectionInformation.SetRawXml(rawXml);
            }
            return section;
        }

        internal bool IsAspNetCompatibilityEnabled()
        {
            ServiceHostingEnvironmentSection section = this._configuration.GetSection("system.serviceModel/serviceHostingEnvironment") as ServiceHostingEnvironmentSection;
            return ((section != null) && section.AspNetCompatibilityEnabled);
        }

        internal bool IsEndpointDeclared(string endpointName)
        {
            DomainServicesSection section = this._configuration.GetSection("system.serviceModel/domainServices") as DomainServicesSection;
            return ((section != null) && section.Endpoints.OfType<ProviderSettings>().Any<ProviderSettings>(p => string.Equals(p.Name, endpointName, StringComparison.OrdinalIgnoreCase)));
        }

        internal bool IsMultipleSiteBindingsEnabled()
        {
            ServiceHostingEnvironmentSection section = this._configuration.GetSection("system.serviceModel/serviceHostingEnvironment") as ServiceHostingEnvironmentSection;
            return ((section != null) && section.MultipleSiteBindingsEnabled);
        }

        internal void SetAspNetCompatibilityEnabled(bool enabled)
        {
            ServiceHostingEnvironmentSection section = this._configuration.GetSection("system.serviceModel/serviceHostingEnvironment") as ServiceHostingEnvironmentSection;
            if (section != null)
            {
                section.AspNetCompatibilityEnabled = enabled;
            }
        }

        internal void SetMultipleSiteBindingsEnabled(bool enabled)
        {
            ServiceHostingEnvironmentSection section = this._configuration.GetSection("system.serviceModel/serviceHostingEnvironment") as ServiceHostingEnvironmentSection;
            if (section != null)
            {
                section.MultipleSiteBindingsEnabled = enabled;
            }
        }
    }
}

